from expression import expression
from expression import environment
from functionDef import functionDef
from customExceptions import ReturnExcpt, GeneralException
from endvals import void


class application(expression):
	def __init__(self, name, args):
		self.args = []
		self.name = name
		self.args = args
		
	#applies closures
	def evaluate(self, env):
	
		function = env.getVarRef(self.name)
		#print "\nApp: ", self.name, " called\n",
		params = function.getParams()
		#print "params: ", params, "\n",
		#print "args: ", self.args, "\n",
		
		#append arguments, with correct bindings, to new enviroment
		#call function body
		
		if(len(self.args) != len(params)):
			raise GeneralException("Function call to Function " + str(self.name) + " Has " + str(len(self.args)) + " args expected "+ str(len(params)))
		else:
			newEnv = function.getEnv()
			#print "arg Values:",
			for arg, param in zip(self.args, params):
				# I think this line should do this:
				# for each parameter in the function, add a variable('x') to the envrionment
				# 'x' has the value of the associated argument, passed in the application
				# In addition, the new environment ('newEnv') is updated as params are added
				# but the old env ('env') is not updated - not that all the argument evaluations
				# use 'env'. I think this is the way to do it.
				thisArg = arg.evaluate(env)
				#print param, "(", thisArg, "),",
				newEnv = environment(param, thisArg, newEnv) 
			#print "\n",
			try:
				function.evaluate(newEnv)
				return void()
			except ReturnExcpt, ret:
				return ret.getValue()

		
